package com.aoip.telemetry.telemetry.analysis.decode;

import com.aoip.telemetry.telemetry.core.config.ElementAnalysisConfig;
import com.aoip.telemetry.telemetry.entity.element.ElementConfigEntity;
import com.aoip.telemetry.telemetry.entity.element.ElementMessageEntity;
import com.aoip.telemetry.telemetry.entity.common.OriginalMessageEntity;
import com.aoip.telemetry.telemetry.entity.common.OriginalMonitoringDataEntity;
import com.aoip.telemetry.telemetry.entity.sn.SnHydrologyEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import static java.util.regex.Pattern.compile;

/**
 * 水文协议，第三轮解析：解析报文中具体的元素指标数据，
 *
 * @author chenbai
 * @version 1.0
 * @date 2021/7/12 3:10
 */
@Component
@Slf4j
public class SnHydrologyElementDataDecode {

    private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
    private static final DateTimeFormatter DATE_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");

    @Resource
    private ElementAnalysisConfig config;

    /**
     * @param msg         元素数据区域
     * @param originalMsg 原始报文
     * @return java.util.List<com.aoip.telemetry.telemetry.entity.element.ElementMessageEntity>
     * @author chenbai
     * @date 2021/8/12
     **/
    public Map<String, Object> elementDataDecode(String msg, OriginalMessageEntity originalMsg, SnHydrologyEntity entity) {
        Map<String, Object> map = new HashMap<>(2);
        String stCd = originalMsg.getStCode();
        String functionCode = originalMsg.getFunctionCode();
        List<ElementConfigEntity> list = config.getStAnalysis(stCd, functionCode);
        List<ElementMessageEntity> elementList = new ArrayList<>();
        List<OriginalMonitoringDataEntity> monitoringDataEntityList = new ArrayList<>();
        map.put("elementList", elementList);
        map.put("monitoringDataEntityList", monitoringDataEntityList);
        int length = msg.length();
        int index = 0;
        if (stCd.endsWith("11111111")) {
            log.error("msg:{};originalMsg:{}", msg, originalMsg);
        }
        while (StringUtils.hasText(msg) && index < length) {
            StringBuilder keyBuild = new StringBuilder();
            while (true) {
                if (msg.length() < index + 1) {
                    return map;
                }
                String temp = msg.substring(index, ++index);
                if ("/".equals(temp)) {
                    continue;
                }
                if (" ".equals(temp)) {
                    break;
                }
                keyBuild.append(temp);
            }
            String identifier = keyBuild.toString();
            if (stCd.endsWith("11111111")) {
                log.error("identifier:{}", identifier);
            }
            for (ElementConfigEntity item : list) {
                String key = item.getIdentifierValue();
                if (!StringUtils.hasText(key)) {
                    continue;
                }
                if (!identifier.equals(key)) {
                    continue;
                }
                StringBuilder sb = new StringBuilder();
                Object value;
                while (true) {
                    String temp = msg.substring(index, ++index);
                    if ("/".equals(temp)) {
                        break;
                    }
                    if (" ".equals(temp)) {
                        break;
                    }
                    sb.append(temp);
                }
                String val = sb.toString();
                if (!StringUtils.hasText(val)) {
                    continue;
                }
                // 小数位
                Integer radixPointBit = item.getRadixPointBit();
                int[] pnArray = new int[11];
                int pni = 0;
                String codingFormat = item.getCodingFormat();
                switch (codingFormat) {
                    case "PN05":
                        int pnIndex = index;
                        while(true) {
                            StringBuilder pn = new StringBuilder();
                            while (true) {
                                String temp = msg.substring(pnIndex, ++pnIndex);
                                if ("/".equals(temp)) {
                                    break;
                                }
                                if (" ".equals(temp)) {
                                    break;
                                }
                                pn.append(temp);
                            }
                            String s = pn.toString();
                            if (!isInteger(s)) {
                                break;
                            }
                            Integer integer = Integer.valueOf(s);
                            pnArray[pni++] = integer;
                        }
                        if (pni == 0 ) {
                            BigDecimal initValue = new BigDecimal(Integer.valueOf(val));
                            value = initValue.divide(BigDecimal.valueOf(Math.pow(10, radixPointBit)), radixPointBit, BigDecimal.ROUND_HALF_UP);
                            index = pnIndex;
                            break;
                        }
                        if (pni == 11 ) {
                            BigDecimal initValue = new BigDecimal(Integer.valueOf(val));
                            BigDecimal sumValue = initValue.divide(BigDecimal.valueOf(Math.pow(10, radixPointBit)), radixPointBit, BigDecimal.ROUND_HALF_UP);
                            for (int i : pnArray) {
                                BigDecimal intVal = BigDecimal.valueOf(i);
                                sumValue = sumValue.add( intVal.divide(BigDecimal.valueOf(Math.pow(10, radixPointBit)), radixPointBit, BigDecimal.ROUND_HALF_UP));
                            }
                            value = sumValue;
                            index = pnIndex;
                            break;
                        }
                        value = "";
                        break;
                    case "MMddHHmm":
                        LocalDateTime dateTime = LocalDateTime.now();
                        LocalDateTime localDateTime;
                        if (val.length() <= 8) {
                            int year = dateTime.getYear();
                            String timeStr = year + val + "00";
                            localDateTime = LocalDateTime.parse(timeStr, DTF);
                        } else {
                            localDateTime = LocalDateTime.parse(val, DATE_TIME);
                        }
                        value = localDateTime;
                        if ("TT".equals(key)) {
                            entity.setObservationTime(localDateTime);
                            originalMsg.setMonitoringTime(localDateTime);
                        }
                        break;
                    case "el":
                        // 经度
                        value = val.substring(0, 3) + "°" + val.substring(3, 5) + "′" + val.substring(5) + "″";
                        break;
                    case "nl":
                        // 纬度
                        value = val.substring(0, 2) + "°" + val.substring(2, 4) + "′" + val.substring(4) + "″";
                        break;
                    default:
                        BigDecimal intVal = BigDecimal.valueOf(Integer.valueOf(val));
                        value = intVal.divide(BigDecimal.valueOf(Math.pow(10, radixPointBit)), radixPointBit, BigDecimal.ROUND_HALF_UP);
                        break;
                }
                String identifierMsg = item.getIdentifierMsg();
                monitoringData(monitoringDataEntityList, identifierMsg, value);
                String tableName = item.getTableName();
                String fieldName = item.getFieldName();
                if (stCd.endsWith("11111111")) {
                    log.error("tableName:{};fieldName:{};value:{}", tableName, fieldName, value);
                }
                if (StringUtils.hasText(tableName) && StringUtils.hasText(fieldName)) {
                    ElementMessageEntity element = new ElementMessageEntity();
                    element.setTableName(tableName);
                    element.setFiledName(fieldName);
                    element.setValue(value);
                    element.setElementConfigEntity(item);
                    elementList.add(element);
                    if ("PN05".equals(codingFormat)) {
                        if (pni == 0 || pni == 11) {
                            ElementMessageEntity pnElement = new ElementMessageEntity();
                            pnElement.setTableName(tableName);
                            pnElement.setFiledName("INTV");
                            if (pni == 0) {
                                pnElement.setValue("0.25");
                            }
                            if (pni == 11 ) {
                                pnElement.setValue("1");
                            }
                            pnElement.setElementConfigEntity(item);
                            elementList.add(pnElement);
                        }
                    }
                }
                break;
            }
        }
        return map;
    }

    private void monitoringData(List<OriginalMonitoringDataEntity> monitoringDataEntityList, String identifierMsg, Object value) {
        OriginalMonitoringDataEntity monitoringDataEntity = new OriginalMonitoringDataEntity();
        monitoringDataEntity.setMonitoringDataIdentifier(identifierMsg);
        monitoringDataEntity.setMonitoringDataValue(value);
        monitoringDataEntityList.add(monitoringDataEntity);
    }

    public static void main(String[] args) {
        System.out.println(isInteger("aaa"));
        System.out.println(isInteger("a123"));
        System.out.println(isInteger("123"));
        System.out.println(isInteger("-123"));
        System.out.println(isInteger("-1.23"));
        System.out.println(isInteger("1.23"));

        System.out.println(Integer.valueOf("aaa"));
        System.out.println(Integer.valueOf("a12"));
    }

    public static boolean isInteger(String str) {
        Pattern pattern = compile("^[-\\= ]?[\\d]*$");
        return pattern.matcher(str).matches();
    }
}
